package jogoKing.leilao;

import ServidorKing.LigacaoJogo;
import baralho.carta.Naipe;
import jogador.Contador;
import jogador.Jogador;
import verificacao.Jogadorvalor;
import verificacao.Pontuacao;

public class Leilao {
	
	private Jogador jogador_que_oferece;
	private Pontuacao pontuacao;
	private boolean modos_positivo;
	private static final int pontuacao_nova = -75;
	private static final int bonus_nulo = 300;
	private LigacaoJogo ligacao_jogo;

	public Leilao(Jogador[] jogadores, LigacaoJogo ligacao_jogo){
		assert jogadores != null;
		this.jogador_que_oferece = null;
		this.pontuacao = new Pontuacao(jogadores);
		this.modos_positivo = true;
		this.ligacao_jogo = ligacao_jogo;
	}

	public Naipe start(Jogador[] jogadores, Jogador dono_leilao, int pontuacao_pos)throws Exception {
		assert(jogadores != null && dono_leilao != null);
		informaQuemEDono(jogadores, dono_leilao);
		if(dono_leilao.haLeilao(ligacao_jogo)){	//o dono do leilao decide se ha um leilao
			Contador c = new Contador(jogadores);
			Jogadorvalor oferta_mais_alta = new Jogadorvalor(dono_leilao, 0);
			int posicao_oferta=0;
			c.entraJogadorJogo(dono_leilao);
			int indice_jogador_actual = 0;
			int valor_oferta = 0;

			while(c.length() > 1){	//2=jogador que oferece pontos + dono do leilao
				if(c.jogadorActual().equals(dono_leilao)){
					//verificar condicoes para 4-3-3-3
					if(c.length() == 2 && oferta_mais_alta.getValor() != 0){
						c.tiraJogador(dono_leilao);
					}
					indice_jogador_actual = 0;
				}else if(c.length() != 2){	//se nao e o dono do leilao e nao e o ultimo jogador no leilao
					informaQuemOferece(jogadores, c.jogadorActual());
					valor_oferta = 0;
					if (indice_jogador_actual < posicao_oferta) {	// Se o jogador nao tiver a maior oferta
						valor_oferta = c.jogadorActual().aumentaOferta(oferta_mais_alta.getValor(), true, ligacao_jogo);	// pode igualar.
					} else {
						valor_oferta = c.jogadorActual().aumentaOferta(oferta_mais_alta.getValor(), false, ligacao_jogo); // Se o jogador tiver a maoir oferta tem que
						// superar o valor porque um jogador a
						// esquerda igualou.
					}

//					for(Jogador j: jogadores){
//						j.getOutputStream().writeObject(new MObject<String>(TipoMensagem.SERVIDOR_LEILAO_INFORMA, "" + c.jogadorActual().getNome() + " " + valor_oferta));
//					}
					
					if (valor_oferta == 0) {
						informaOfertaActual(jogadores, new Jogadorvalor(c.jogadorActual(), valor_oferta));
						c.tiraJogador(c.jogadorActual());
						if(posicao_oferta > indice_jogador_actual){
							posicao_oferta++;
						}
						for(int i=1; i<c.length(); i++){	//jogador antes do jogador tirado
							c.proximoJogador();
						}
					} else if (valor_oferta >= oferta_mais_alta.getValor()
							|| valor_oferta * -3 >= oferta_mais_alta.getValor()) {
						oferta_mais_alta.setValor(valor_oferta);
						oferta_mais_alta.setJogador(c.jogadorActual());
						posicao_oferta = indice_jogador_actual;
					}
				}
				if(valor_oferta != 0){
					informaOfertaActual(jogadores, new Jogadorvalor(c.jogadorActual(), valor_oferta));
				}
				indice_jogador_actual++;
				c.proximoJogador();
			}

			
			///////////////////////////////////////////////////////////////////
			
			//Jogador vencedor do Leilao e dono do leilao continuam
			if(oferta_mais_alta.getJogador().equals(dono_leilao)){	//nenhum jogador ofereceu vazas
				if(dono_leilao.quatroTresTres(ligacao_jogo)){
					this.informaMensagem(jogadores, "O dono do leilao deseja jogar 4-3-3-3");
					throw new Exception("O dono do leilao deseja jogar 4-3-3-3");	
				}else{
					escolheTrunfo(dono_leilao);
				}
			}else{
				int of = 0;
				while(oferta_mais_alta.getValor()!=0 && !dono_leilao.aceitaOferta(oferta_mais_alta.getValor(), ligacao_jogo)){	//continua enquanto o dono do leilao nao aceitar e o outro jogador estar disposto a aumentar.
					of = oferta_mais_alta.getJogador().aumentaOferta(oferta_mais_alta.getValor(), false, ligacao_jogo);
					oferta_mais_alta.setValor(of);
					this.informaOfertaActual(jogadores, oferta_mais_alta);
				}
				
				if(oferta_mais_alta.getValor()!=0){
						this.informaMensagem(jogadores, "O Dono do leilao aceitou a oferta");
				}

				this.jogador_que_oferece = oferta_mais_alta.getJogador();
				if(oferta_mais_alta.getValor() != 0){	//se houver uma oferta valida, o jogador que ofereceu e o vencedor do leilao. Senao continua a ser o dono do leilao
					Naipe naipe_escolhido = null;
					this.jogador_que_oferece = oferta_mais_alta.getJogador();
					if(oferta_mais_alta.getValor()>0){	//Se a oferta e positiva o Jogador deve escolher o trunfo.
						naipe_escolhido = this.jogador_que_oferece.escolheTrunfo(ligacao_jogo);
						this.pontuacao.actualizaPontuacaoJogador(this.jogador_que_oferece, -oferta_mais_alta.getValor()*pontuacao_pos);
						this.pontuacao.actualizaPontuacaoJogador(dono_leilao, oferta_mais_alta.getValor()*pontuacao_pos);
					}else{	//A oferta nao e positiva. Como e negativa, nao ha trunfo.
						naipe_escolhido = null;
						this.modos_positivo = false;
						this.pontuacao.actualizaPontuacaoJogador(this.jogador_que_oferece, oferta_mais_alta.getValor()*pontuacao_nova);
						this.pontuacao.actualizaPontuacaoJogador(dono_leilao, -oferta_mais_alta.getValor()*pontuacao_nova);
					}
					return naipe_escolhido;
				}else{
					return escolheTrunfo(dono_leilao);
				}
			}
		}else{	//O dono do leilao escolheu que nao ha leilao neste minijogo positivo.
				this.informaMensagem(jogadores, "Nao ha leilao!");
			return escolheTrunfo(dono_leilao);
		}
		return null;
	}

	private void informaQuemEDono(Jogador[] jogadores, Jogador dono_leilao) {
		for(Jogador j: jogadores){
			j.informaQuemEDono(dono_leilao.getNome());
		}
	}
	

	private void informaQuemOferece(Jogador[] jogadores, Jogador dono_leilao) {
		for(Jogador j: jogadores){
			j.informaQuemOferece(dono_leilao.getNome());
		}
	}

	private void informaOfertaActual(Jogador[] jogadores, Jogadorvalor oferta_mais_alta){
		
		for(Jogador j: jogadores){
			j.informaOfertaActual(new JogadorOferta(oferta_mais_alta.getJogador().getNome(), oferta_mais_alta.getValor()));
		}
	}

	private Naipe escolheTrunfo(Jogador jogador){
		assert(jogador != null);
		RespostasLeilao resposta = jogador.negativo(this.ligacao_jogo);
		
		if(resposta == RespostasLeilao.NEGATIVO){
			this.modos_positivo = false;
			return null;
		}
		if(resposta == RespostasLeilao.SEM_TRUNFO) return null;
		if(resposta == RespostasLeilao.TRUNFO_OUROS) return Naipe.Ouros;
		if(resposta == RespostasLeilao.TRUNFO_COPAS) return Naipe.Copas;
		if(resposta == RespostasLeilao.TRUNFO_ESPADAS) return Naipe.Espadas;
		if(resposta == RespostasLeilao.TRUNFO_PAUS) return Naipe.Paus;
		return null;
	}
	
	private void informaMensagem(Jogador[] jogadores, String mensagem){
		for(Jogador j: jogadores){
			j.informaMensagem(mensagem);
		}
	}
	
	public Pontuacao modificaPontuacao(Pontuacao pontuacao, Jogador dono_leilao, int pontuacao_pos) {
		assert(pontuacao != null && dono_leilao != null);
		if(!modos_positivo){
			if(this.jogador_que_oferece != null && dono_leilao != null && pontuacao.getPontuacao(this.jogador_que_oferece) > this.pontuacao.getPontuacao(this.jogador_que_oferece)){	//Se o jogador nao fez as vazas que ele ofereceu, ele so pode dar as vazas que ele fez.
				this.pontuacao.setPontuacao(this.jogador_que_oferece, -pontuacao.getPontuacao(this.jogador_que_oferece));
				this.pontuacao.setPontuacao(dono_leilao, pontuacao.getPontuacao(dono_leilao));
			}
			pontuacao.muda(pontuacao_pos, pontuacao_nova);
			pontuacao.actualizaPontuacaoTodos(bonus_nulo);
		}else{
			if(this.jogador_que_oferece != null && dono_leilao != null && pontuacao.getPontuacao(this.jogador_que_oferece) < this.pontuacao.getPontuacao(this.jogador_que_oferece)){	//Se o jogador nao 
				this.pontuacao.setPontuacao(this.jogador_que_oferece, -pontuacao.getPontuacao(this.jogador_que_oferece));
				this.pontuacao.setPontuacao(dono_leilao, pontuacao.getPontuacao(dono_leilao));
			}
		}
		pontuacao.actualizaPontuacao(this.pontuacao);
		return pontuacao;
	}
}